package com.um.jdy.app.device.manager;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.um.jdy.app.charge.manager.PBOrderManager;
import com.um.jdy.common.charge.entity.po.Order;
import com.um.jdy.common.charge.enums.OrderAction;
import com.um.jdy.common.charge.enums.OrderEnum;
import com.um.jdy.common.charge.enums.OrderStopReason;
import com.um.jdy.common.charge.service.OrderService;
import com.um.jdy.common.device.entity.po.Gun;
import com.um.jdy.common.device.entity.po.Pile;
import com.um.jdy.common.device.enums.DeviceEnum;
import com.um.jdy.common.device.service.GunService;
import com.um.jdy.common.device.service.OnlineLogService;
import com.um.jdy.common.device.service.PileService;
import com.um.jdy.common.push.service.PushService;
import com.um.jdy.rpc.entity.PBDeviceInfo;
import com.um.jdy.rpc.entity.PBPort;
import com.um.jdy.rpc.entity.xh.PBXhParamsDTO;
import com.um.jdy.rpc.enums.DeviceIotEnum;
import com.um.jdy.rpc.factory.ServiceFactory;
import com.um.jdy.rpc.notify.RpcPBDeviceNotifyService;
import com.um.springboot.starter.utils.StringUtil;
import com.um.springcloud.dubbo.cluster.DeviceKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 充电宝设备处理逻辑
 * @Description
 * @Author dnannhui
 * @Date 2023/5/22 10:37
 */
@Slf4j
@Service
@DubboService
public class PBDeviceManager implements RpcPBDeviceNotifyService {

    @Autowired
    ServiceFactory serviceFactory;

    @Autowired
    PileService pileService;

    @Autowired
    GunService gunService;

    @Autowired
    PBOrderManager pbOrderManager;

    @Autowired
    OrderService orderService;

    @Autowired
    OnlineLogService onlineLogService;

    @Autowired
    PushService pushService;

    /**
     * 设备登录上报
     *
     * @param seq   序列号
     * @param imei  IMEI码
     * @param ports 端口列表
     * @param info  设备信息
     */
    @Override
    public void reqDeviceLogin(String cmd, String seq, String imei, List<PBPort> ports, PBDeviceInfo info) {

        Pile devicePile = pileService.getRow("imei",imei);
        if(devicePile == null){
            try {
                info.setHeart(60);
                info.setPortHeart(1800);
                info.setResult(0);
                serviceFactory.getRpcPBDeviceService(info.getProtocol()).respDeviceLogin(seq, new DeviceKey(imei), info);
            } catch (Exception ex) {
                log.error("回复失败-Cmd01HeartResp", ex);
            }
            return;
        }else{
            try {
                info.setHeart(60);
                info.setPortHeart(1800);
                info.setResult(1);
                serviceFactory.getRpcPBDeviceService(info.getProtocol()).respDeviceLogin(seq, new DeviceKey(imei), info);
            } catch (Exception ex) {
                log.error("回复失败-Cmd01HeartResp", ex);
            }
        }



        onlineLogService.addOnline(devicePile.getCode(),devicePile.getName());

        //修改为在线状态,上报状态正常,更新上线时间
        devicePile.setRssi(info.getRssi());
        devicePile.setIccid(info.getIccid());
        devicePile.setVersion(info.getVersion());
        devicePile.setOpenState(DeviceEnum.OpenStatus.Enable.name());
        devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
        devicePile.setLastOnlineTime(new Date());
        devicePile.setIpAddress(info.getIpAddress());
        devicePile.setProtocol(info.getProtocol());
        if(devicePile.getParameters() == null || StrUtil.isEmpty(devicePile.getParameters())){
            devicePile.setParameters(serviceFactory.getDeviceParameters(devicePile.getDeviceType(),info.getProtocol()));
        }
        pileService.updateRow(devicePile);

        if (devicePile != null || null != ports) {
            updatePortsStatus(devicePile.getDevicePileId(), ports);
        }


    }

    /**
     * 设备离线上报
     *
     * @param imei IMEI码
     */
    @Override
    public void reqDeviceOffline(String imei) {
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        //推送
        pushService.pushDeviceOffline(devicePile);
    }

    /**
     * 设备心跳上报
     *
     * @param seq  序列号
     * @param imei IMEI码
     */
    @Override
    public void reqDeviceHeart(String cmd, String seq, String imei,String protocol) {
        try {
            serviceFactory.getRpcPBDeviceService(protocol).respDeviceHeart(seq,new DeviceKey(imei),60);
        }catch (Exception ex){
            log.error("回复失败-Cmd01HeartResp", ex);
        }

        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        devicePile.setProtocol(protocol);
        devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
        devicePile.setHeartTime(new Date());
        pileService.updateRow(devicePile);

    }

    /**
     * 回复设备重启
     *
     * @param seq  序列号
     * @param imei IMEI码
     */
    @Override
    public void respRestart(String cmd, String seq, String imei) {

    }

    /**
     * 回复端口状态查询
     *
     * @param seq   序列号
     * @param imei  IMEI码
     * @param ports 端口列表
     */
    @Override
    public void respQueryPorts(String cmd, String seq, String imei, List<PBPort> ports) {
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        if(!devicePile.getDeviceStatus().equals(DeviceEnum.DeviceStatus.Online.name())) {
            devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
            devicePile.setHeartTime(new Date());
            pileService.updateRow(devicePile);
        }

        updatePortsStatus(devicePile.getDevicePileId(),ports);
    }

    /**
     * 回复强制打开端口
     *
     * @param seq        序列号
     * @param imei       IMEI码
     * @param state 租用结果 0 为正常，1 为没有充电宝，2 为无可租用，4 超时
     * @param ports      打开端口列表
     */
    @Override
    public void respOpenPort(String command,String seq, String imei,Integer state, List<PBPort> ports){

        //暂时不用处理业务
        log.info("cmd:{},seq:{},imei:{},state:{},ports:{}",command,state,imei,state,ports);
    }

    /**
     * 沃诗设备更新设备信息
     * @param command
     * @param seq
     * @param imei
     * @param deviceInfo
     */
    @Override
    public void respDeviceInfo(String command, String seq, String imei, PBDeviceInfo deviceInfo) {
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        if(!StringUtil.isEmpty(deviceInfo.getIccid()))
            devicePile.setIccid(deviceInfo.getIccid());

        if(!StringUtil.isEmpty(deviceInfo.getRssi()))
            devicePile.setRssi(deviceInfo.getRssi());

        if(!StringUtil.isEmpty(deviceInfo.getVersion()))
            devicePile.setVersion(deviceInfo.getVersion());

        if(!StringUtil.isEmpty(deviceInfo.getHeart()))
            devicePile.setHeart(deviceInfo.getHeart());

        if(!StringUtil.isEmpty(deviceInfo.getDomain())) {

            PBXhParamsDTO params = new PBXhParamsDTO();
            params.setDomain(deviceInfo.getDomain());
            params.setPort(deviceInfo.getPort());
            params.setHeart(deviceInfo.getHeart());

            devicePile.setParameters(JSONUtil.toJsonStr(params));
        }

        pileService.updateRow(devicePile);
    }


    /**
     * 更新充电宝端口的状态
     * @param devicePileId
     * @param ports
     */
    @Transactional
    public void updatePortsStatus(String devicePileId,List<PBPort> ports){
        List<Gun> listGun = gunService.getRows("device_pile_id",devicePileId,"port","asc");
        for(Gun gun : listGun){

            boolean hasPowerBank = false;

            for(PBPort port : ports){
                if(gun.getPort() == port.getPort()){
                    //更新充电宝端口
                    gun.setSoc(port.getSoc());
                    gun.setSn((StringUtil.isEmpty(port.getSn()) || port.getSn().equals("NULL"))? "" : port.getSn());
                    gun.setStatus(port.getState());
                    gunService.updateRow(gun);

                    //如果有订单未归还的，则自动归还
                    Order order = orderService.getViewModel("get_pb_order_by_sn", Order.class,
                            new String[]{port.getSn(), OrderEnum.Status.Charging.name(),gun.getComId()});
                    if(order != null) {
                        pbOrderManager.saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.PB.DeviceStatusReq,
                                port,"设备归还成功，SN码为："+port.getSn());
                        pbOrderManager.rentFinish(order.getOrderNo(), OrderStopReason.PB.OVERTIME.name(),devicePileId, port.getPort(), false, false);
                    }
                    hasPowerBank = true;
                    break;
                }
            }

            if(!hasPowerBank){//没有充电宝，设为空
                gun.setSoc(0);
                gun.setSn("");
                gun.setStatus(DeviceEnum.PortStatus.Available.name());
                gunService.updateRow(gun);
            }
        }
    }

}
